package com.studerb.view.newsGroups;

import static com.studerb.util.Constants.EVENT_SERVICE_NAME;

import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.table.AbstractTableModel;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;
import org.bushe.swing.event.annotation.AnnotationProcessor;
import org.bushe.swing.event.annotation.EventSubscriber;
import org.springframework.beans.factory.annotation.Autowired;

import com.studerb.events.NewsGroupEvent;
import com.studerb.model.NewsGroup;
import com.studerb.service.interfaces.INewsGroupService;

public class NewsGroupsTableModel extends AbstractTableModel {
	private static final Logger logger = Logger.getLogger(NewsGroupsTableModel.class);

	private final static Class[] columnClasses = new Class[] { String.class, Integer.class, Boolean.class };
	private final static String[] columnNames = new String[] { "Group", "Posts", "Subscribed" };
	private final static boolean[] isEditable = new boolean[] { Boolean.FALSE, Boolean.FALSE, Boolean.TRUE };
	@Autowired protected INewsGroupService newsGroupService;

	@Autowired protected NewsGroupsPane newsGroupsPane;
	protected List<NewsGroup> newsGroups;

	private void changeSubscribed(Boolean subscribed, int rowIndex) {
		NewsGroup group = this.getNewsGroup(rowIndex);
		String messageText;
		if (subscribed) {
			messageText = "Subscribe to Group: " + group.getGroupName();
		}
		else {
			messageText = "Unsubscribe from Group: " + group.getGroupName() + " All downloaded headers will be purged";
		}
		int option = JOptionPane.showConfirmDialog(newsGroupsPane, messageText);
		if (option == JOptionPane.YES_OPTION) {
			subscribeGroup(group, subscribed);
		}
	}

	@Override public Class getColumnClass(int columnIndex) {
		return columnClasses[columnIndex];
	}

	@Override public int getColumnCount() {
		// columns: Group Name, header count, isSubsribed
		return columnNames.length;
	}

	@Override public String getColumnName(int column) {
		return columnNames[column];
	}

	public NewsGroup getNewsGroup(int row) {
		return newsGroups.get(row);
	}

	@Override public int getRowCount() {
		return newsGroups.size();
	}

	@Override public Object getValueAt(int rowIndex, int columnIndex) {
		NewsGroup newsGroup = newsGroups.get(rowIndex);
		switch (columnIndex) {
		case 0:
			return newsGroup.getGroupName();
		case 1:
			return newsGroup.getPostsCount();
		case 2:
			return newsGroup.isSubscribed();
		default:
			throw new IllegalArgumentException("Should never have newsgroup column index of: " + columnIndex);
		}
	}

	public void init() {
		newsGroups = newsGroupService.getNewsGroups();
		AnnotationProcessor.process(this);
	}

	@Override public boolean isCellEditable(int rowIndex, int columnIndex) {
		return isEditable[columnIndex];
	}

	@EventSubscriber(eventServiceName = EVENT_SERVICE_NAME) public void onEvent(NewsGroupEvent evt) {
		NewsGroup newsGroup;
		NewsGroupEvent.EventType eventType = evt.getType();
		switch (eventType) {
		case ALL_REFRESHED:
			newsGroups = newsGroupService.getNewsGroups();
			logger.debug("Firing tabledatachanged");
			fireTableDataChanged();
			break;
		case UPDATED:
			newsGroup = evt.getNewsGroup();
			int index = newsGroups.indexOf(newsGroup);
			if (index == -1) {
				throw new RuntimeException("no version of updated newsgroup in tablemodel list");
			}
			fireTableRowsUpdated(index, index);
			break;
		default:
			break;
		}
	}

	@Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
		if (columnIndex == Column.SUBSCRIBED.ordinal()) {
			changeSubscribed((Boolean) aValue, rowIndex);
		}
	}

	private void subscribeGroup(NewsGroup group, boolean subscribed) {
		try {
			logger.debug("setting subscribed = " + subscribed + " for group: " + group.getGroupName());
			if (subscribed) {
				newsGroupService.subscribe(group);
			}
			else {
				newsGroupService.unsubscribe(group);
			}
		}
		catch (Exception e) {
			JOptionPane.showMessageDialog(newsGroupsPane, "Error updating Newsgroup: " + ExceptionUtils.getRootCauseMessage(e));
		}
	}

	public enum Column {
		GROUP, HEADER_COUNT, SUBSCRIBED
	}
}
